//
//  NetworkingManager.m
//  YuanXinNetWorking
//
//  Created by 晏德智 on 2016/12/7.
//  Copyright © 2016年 晏德智. All rights reserved.
//

#import "NetworkingManager.h"
#import "AFOAuthManager.h"
#import "AFOAuthCredential.h"
#import "NSString+URL.h"
#import "YuanXinJSONResponseSerializer.h"
#import "AFHTTPSessionManager+BackwardCompatible.h"

#define networkRefreshToken @"refreshToken"

typedef void (^TryAgainBlock)();

@interface NetworkingManager() <OAuthInfoObserver> // 自己也遵守协议，为了转发别处的请求

@property (nonatomic, strong) AFOAuthManager *defaultManager;

//还原Tokenkey
@property (nonatomic, strong) NSString *serviceProviderIdentifier;

@property (nonatomic, strong) NSURLSessionConfiguration *configuration;

@property (readwrite, nonatomic, strong) AFOAuthCredential *credential;

//@property (nonatomic, strong) AFJSONResponseSerializer *responseSerializer;
@property (nonatomic, strong) YuanXinJSONResponseSerializer *responseSerializer;

@property (nonatomic, strong) AFJSONRequestSerializer *requestSerializer;

@property (nonatomic, strong) NSMutableArray<id<OAuthInfoObserver>> *oauthObservers;

@property (nonatomic, assign) BOOL triedAgain; // for 401
@property (nonatomic, strong) NSMutableArray<TryAgainBlock> *arryTryAgain; // for 401

@end

@implementation NetworkingManager

+ (instancetype)shareInstance{
    static NetworkingManager *_networkingManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _networkingManager = [[NetworkingManager alloc] init];
    });

    return _networkingManager;
}

- (instancetype)init{
    self = [super init];
    if(self){
        _configuration= [NSURLSessionConfiguration defaultSessionConfiguration];
        _configuration.timeoutIntervalForRequest = 120.0;
        _configuration.timeoutIntervalForResource = 120.0;
        _timeoutInterval = 30;
        _responseSerializer = [YuanXinJSONResponseSerializer serializer];
        _requestSerializer = [AFJSONRequestSerializer serializer];
        _oauthObservers = [[NSMutableArray<id<OAuthInfoObserver>> alloc] init];

        self.arryTryAgain = [[NSMutableArray alloc] init];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_refreshToken:) name:networkRefreshToken object:nil];
    }
    return self;
}

#pragma mark -- properties

- (NSString *)bucketNameForIMUploadFile {
    if (!_bucketNameForIMUploadFile) {
#ifdef DEBUG
        _bucketNameForIMUploadFile = @"IM";
#else
        _bucketNameForIMUploadFile = @"IM";
#endif
    }
    return _bucketNameForIMUploadFile;
}

- (AFOAuthCredential *)credential{

    if(!_credential){
        AFOAuthCredential *oauthCredential =[AFOAuthCredential retrieveCredentialWithIdentifier:self.serviceProviderIdentifier];
        if(oauthCredential){
            _credential = oauthCredential;
        }
    }
    return _credential;
}

- (AFOAuthManager *)defaultManager{
    if(!_defaultManager){
        _defaultManager =[[AFOAuthManager alloc] initWithBaseURL:self.baseURL
                                            sessionConfiguration:_configuration
                                                        clientID:self.clientID
                                                          secret:self.clientSecret];
    }

    _defaultManager.requestSerializer = _requestSerializer;
    _defaultManager.responseSerializer = _responseSerializer;
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    [securityPolicy setValidatesDomainName:NO];
    [securityPolicy setAllowInvalidCertificates:YES];
    _defaultManager.securityPolicy = securityPolicy;

    return _defaultManager;
}

//添加对OAuth 服务状态管理
- (void)addOAuthInfoObserver:(id<OAuthInfoObserver>)oauthObserver{
    [_oauthObservers addObject:oauthObserver];
}

//移除当前OAuth 服务状态管理
- (void)removeOAuthInfoObserver:(id<OAuthInfoObserver>)oauthObserver{
    [_oauthObservers removeObject:oauthObserver];
}

- (BOOL)retrieveCredentialWithIdentifier:(NSString *)identifier{
    if(identifier){

        self.serviceProviderIdentifier = identifier;

        AFOAuthCredential *credential =[AFOAuthCredential retrieveCredentialWithIdentifier:identifier];
        if(credential){
            _credential = credential;

            return YES;
        }

    }
    return NO;
}

#pragma mark -- OAuthInfoObserver
//网络请求401时处理
- (void)onUnauthorized {
    if(self.oauthObservers.count > 0){
        for (id<OAuthInfoObserver> oaObserver in self.oauthObservers){
            if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                [oaObserver onUnauthorized];
            }
        }
    }
}

#pragma mark -- methods

- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
                                                 username:(NSString *)username
                                                 password:(NSString *)password
                                                    scope:(NSString *)scope
                                                  success:(void (^)(AFOAuthCredential *credential))success
                                                  failure:(void (^)(NSError *error))failure{

    AFOAuthManager *oAuthManager = self.defaultManager;
    oAuthManager.requestSerializer = [AFHTTPRequestSerializer serializer];
    oAuthManager.requestSerializer.timeoutInterval = self.timeoutInterval;
    __weak typeof (self) weakSelf = self;
    return [oAuthManager authenticateUsingOAuthWithURLString:URLString
                                                    username:username
                                                    password:password
                                                       scope:scope
                                                     success:^(AFOAuthCredential *credential) {
                                                         NSLog(@"Token: %@", credential.accessToken);
                                                         weakSelf.credential =credential;
                                                         /*
                                                          [AFOAuthCredential storeCredential:credential
                                                          withIdentifier:serviceProviderIdentifier];
                                                          */
                                                         if(success){
                                                             success(credential);
                                                         }
                                                     }
                                                     failure:^(NSError *error) {
                                                         NSLog(@"Error: %@", error);
                                                         if(failure){
                                                             failure(error);
                                                         }
                                                     }];

}


- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
                                               parameters:(NSDictionary *)parameters
                                                  success:(void (^)(id responseObject))success
                                                  failure:(void (^)(NSError *error))failure{

    AFOAuthManager *oAuthManager = self.defaultManager;
    oAuthManager.requestSerializer = [AFHTTPRequestSerializer serializer];
    oAuthManager.requestSerializer.timeoutInterval = self.timeoutInterval;
    __weak typeof (self) weakSelf = self;
    return [oAuthManager yuanxinAuthenticateUsingOAuthWithURLString:URLString
                                                         parameters:parameters
                                                            success:^(id responseObject) {

                                                                NSString *refreshToken = [responseObject valueForKey:@"refresh_token"];
                                                                if (!refreshToken || [refreshToken isEqual:[NSNull null]]) {
                                                                    refreshToken = [parameters valueForKey:@"refresh_token"];
                                                                }

                                                                AFOAuthCredential *credential = [AFOAuthCredential credentialWithOAuthToken:[responseObject valueForKey:@"access_token"] tokenType:[responseObject valueForKey:@"token_type"]];


                                                                if (refreshToken) { // refreshToken is optional in the OAuth2 spec
                                                                    [credential setRefreshToken:refreshToken];
                                                                }

                                                                // Expiration is optional, but recommended in the OAuth2 spec. It not provide, assume distantFuture === never expires
                                                                NSDate *expireDate = [NSDate distantFuture];
                                                                id expiresIn = [responseObject valueForKey:@"expires_in"];
                                                                if (expiresIn && ![expiresIn isEqual:[NSNull null]]) {
                                                                    expireDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]];
                                                                }

                                                                if (expireDate) {
                                                                    [credential setExpiration:expireDate];
                                                                }

                                                                weakSelf.credential = credential;
                                                                NSLog(@"Token: %@", credential.accessToken);

                                                                [AFOAuthCredential storeCredential:credential
                                                                                    withIdentifier:self.serviceProviderIdentifier];


                                                                if(success){
                                                                    success(responseObject);
                                                                }
                                                            }
                                                            failure:^(NSError *error) {
                                                                NSLog(@"Error: %@", error);
                                                                if(failure){
                                                                    failure(error);
                                                                }
                                                            }];

}

- (void)handle401:(NSURLSessionDataTask *)task error:(NSError *)error block:(TryAgainBlock)tryAgainBlock failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
    // 缓存执行
    if (self.arryTryAgain) {
        [self.arryTryAgain addObject:tryAgainBlock];
        // 设置超时
        dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
        dispatch_after(delayTime, dispatch_get_main_queue(), ^{
            if ([self.arryTryAgain containsObject:tryAgainBlock]) {
                [self.arryTryAgain removeObject:tryAgainBlock];
                if(failure){
                    failure(task,error);
                }
            }
        });
    }
}

- (void)_refreshToken:(NSNotification *)notification {
    NSDictionary *obj = (NSDictionary *)notification.object;

    @synchronized (self) {
        for (TryAgainBlock tryAgainBlock in self.arryTryAgain) {
            tryAgainBlock();
        }
        [self.arryTryAgain removeAllObjects];
    }

    self.triedAgain = YES;
}

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(id)parameters
                      success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                      failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    AFOAuthManager *manager = [self getCurrentManagerWithUrl:URLString];
    manager.responseSerializer = self.responseSerializer;
    manager.requestSerializer = self.requestSerializer;
    if(self.credential && self.credential.accessToken){
        [manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_credential];
    }
    __weak typeof (self) weakSelf = self;

    return [manager GET:URLString
             parameters:parameters
               progress:nil
                success:^(NSURLSessionDataTask *task, id _Nullable responseObject){
                    self.triedAgain = NO; // 成功时重置
                    if(success){
                        success(task,responseObject);
                    }
                }
                failure:^(NSURLSessionDataTask * _Nullable task, NSError *error){
                    if(error.code == 401){
                        __strong typeof (weakSelf) strongSelf = weakSelf;
                        if(strongSelf.oauthObservers.count > 0){
                            for (id<OAuthInfoObserver> oaObserver in strongSelf.oauthObservers){
                                if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                                    [oaObserver onUnauthorized];
                                }
                            }
                        }

                        if (self.triedAgain) {
                            self.triedAgain = NO;
                        } else {
                            TryAgainBlock tryAgainBlock = ^(){
                                // 重试一次
                                [strongSelf GET:URLString parameters:parameters success:success failure:failure];
                            };
                            [strongSelf handle401:task error:error block:tryAgainBlock failure:failure];

                            return; // 停掉，重试后再回调
                        }
                    }

                    if(failure){
                        failure(task,error);
                    }
                }];

}

- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(id)parameters
                                success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                                failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    AFOAuthManager *manager = [self getCurrentManagerWithUrl:URLString];
    manager.responseSerializer = self.responseSerializer;
    manager.requestSerializer = self.requestSerializer;
    if(self.credential && self.credential.accessToken){
        [manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_credential];
    }
    __weak typeof (self) weakSelf = self;
    return [manager POST:URLString
              parameters:parameters
                progress:nil
                 success:^(NSURLSessionDataTask *task, id _Nullable responseObject){
                     self.triedAgain = NO; // 成功时重置
                     if(success){
                         success(task,responseObject);
                     }
                 }
                 failure:^(NSURLSessionDataTask * _Nullable task, NSError *error){
                     if(error.code == 401){
                         __strong typeof (weakSelf) strongSelf = weakSelf;
                         if(strongSelf.oauthObservers.count > 0){
                             for (id<OAuthInfoObserver> oaObserver in strongSelf.oauthObservers){
                                 if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                                     [oaObserver onUnauthorized];
                                 }
                             }
                         }

                         if (self.triedAgain) {
                             self.triedAgain = NO;
                         } else {
                             TryAgainBlock tryAgainBlock = ^(){
                                 // 重试一次
                                 [strongSelf POST:URLString parameters:parameters success:success failure:failure];
                             };
                             [strongSelf handle401:task error:error block:tryAgainBlock failure:failure];

                             return; // 停掉，重试后再回调
                         }
                     }

                     if(failure){
                         failure(task,error);
                     }
                 }];
}

- (NSURLSessionDataTask *)PUT:(NSString *)URLString
                   parameters:(nullable id)parameters
                      success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                      failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure{

    AFHTTPSessionManager *manager = [self getCurrentManagerWithUrl:URLString];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    if(self.credential && self.credential.accessToken){
        [manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_credential];
    }
    __weak typeof (self) weakSelf = self;
    return [manager  PUT:URLString
              parameters:parameters
                 success:^(NSURLSessionDataTask *task, id _Nullable responseObject){
                     self.triedAgain = NO; // 成功时重置
                     if(success){
                         success(task,responseObject);
                     }
                 }
                 failure:^(NSURLSessionDataTask * _Nullable task, NSError *error){
                     if(error.code == 401){
                         __strong typeof (weakSelf) strongSelf = weakSelf;
                         if(strongSelf.oauthObservers.count > 0){
                             for (id<OAuthInfoObserver> oaObserver in strongSelf.oauthObservers){
                                 if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                                     [oaObserver onUnauthorized];
                                 }
                             }
                         }

                         if (self.triedAgain) {
                             self.triedAgain = NO;
                         } else {
                             TryAgainBlock tryAgainBlock = ^(){
                                 // 重试一次
                                 [strongSelf PUT:URLString parameters:parameters success:success failure:failure];
                             };
                             [strongSelf handle401:task error:error block:tryAgainBlock failure:failure];

                             return; // 停掉，重试后再回调
                         }
                     }

                     if(failure){
                         failure(task,error);
                     }
                 }];

}

- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
                              parameters:(nullable id)parameters
                                 success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                 failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure{

    AFOAuthManager *manager = [self getCurrentManagerWithUrl:URLString];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    if(self.credential && self.credential.accessToken){
        [manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_credential];
    }

    __weak typeof (self) weakSelf = self;
    return [manager  PATCH:URLString
                parameters:parameters
                   success:^(NSURLSessionDataTask *task, id _Nullable responseObject){
                       self.triedAgain = NO; // 成功时重置
                       if(success){
                           success(task,responseObject);
                       }
                   }
                   failure:^(NSURLSessionDataTask * _Nullable task, NSError *error){
                       if(error.code == 401){
                           __strong typeof (weakSelf) strongSelf = weakSelf;
                           if(strongSelf.oauthObservers.count > 0){
                               for (id<OAuthInfoObserver> oaObserver in strongSelf.oauthObservers){
                                   if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                                       [oaObserver onUnauthorized];
                                   }
                               }
                           }

                           if (self.triedAgain) {
                               self.triedAgain = NO;
                           } else {
                               TryAgainBlock tryAgainBlock = ^(){
                                   // 重试一次
                                   [strongSelf PATCH:URLString parameters:parameters success:success failure:failure];
                               };
                               [strongSelf handle401:task error:error block:tryAgainBlock failure:failure];

                               return; // 停掉，重试后再回调
                           }
                       }

                       if(failure){
                           failure(task,error);
                       }
                   }];
}

- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
                               parameters:(nullable id)parameters
                                  success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                  failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure{

    AFOAuthManager *manager = [self getCurrentManagerWithUrl:URLString];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    if(self.credential && self.credential.accessToken){
        [manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_credential];
    }

    __weak typeof (self) weakSelf = self;
    return [manager DELETE:URLString
                parameters:parameters
                   success:^(NSURLSessionDataTask *task, id responseObject){
                       self.triedAgain = NO; // 成功时重置
                       if(success){
                           success(task,responseObject);
                       }
                   }
                   failure:^(NSURLSessionDataTask *task, NSError *error){
                       if(error.code == 401){
                           __strong typeof (weakSelf) strongSelf = weakSelf;
                           if(strongSelf.oauthObservers.count > 0){
                               for (id<OAuthInfoObserver> oaObserver in strongSelf.oauthObservers){
                                   if([oaObserver respondsToSelector:@selector(onUnauthorized)]){
                                       [oaObserver onUnauthorized];
                                   }
                               }
                           }

                           if (self.triedAgain) {
                               self.triedAgain = NO;
                           } else {
                               TryAgainBlock tryAgainBlock = ^(){
                                   // 重试一次
                                   [strongSelf DELETE:URLString parameters:parameters success:success failure:failure];
                               };
                               [strongSelf handle401:task error:error block:tryAgainBlock failure:failure];

                               return; // 停掉，重试后再回调
                           }
                       }

                       if(failure){
                           failure(task,error);
                       }
                   }];
}

- (NSURLSessionDataTask *)uploadMultiPart:(NSString *)URLString
                               parameters:(id)parameters
                                     data:(NSData *)data
                                  success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                                  failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
    NSURL *URL = [self getCurrentUrl:URLString];
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:URL parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        //[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil];
        [formData appendPartWithFormData:data name:@"files"];
    } error:nil];

    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

    __block  NSURLSessionUploadTask *uploadTask;
    uploadTask = [manager uploadTaskWithStreamedRequest:request
                                               progress:nil
                                      completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                                          if (error) {
                                              if(failure){
                                                  failure(uploadTask,error);
                                              }

                                              NSLog(@"Error: %@", error);
                                          } else {
                                              NSLog(@"%@ %@", response, responseObject);
                                              if(success){

                                              }
                                          }
                                      }];

    [uploadTask resume];

    return uploadTask;
}

- (NSURLSessionDataTask *)uploadFile:(NSString *)URLString
                                data:(NSData *)data
                             headers:(NSDictionary *)headers
                             success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                             failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    AFOAuthManager *manager = nil;
    NSURL *URL = nil;
    if([URLString hasPrefix:@"https://"] || [URLString hasPrefix:@"http://"]){
        URL = [NSURL URLWithString:URLString];
        manager = [[AFOAuthManager alloc] initWithSessionConfiguration:nil];
    }else{
        URL = [NSURL URLWithString:URLString relativeToURL:self.baseURL];
        manager = self.defaultManager;
    }

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    [request setHTTPMethod:@"POST"];

    for (NSString *key in headers) {
        id val = [headers objectForKey:key];
        if ([val respondsToSelector:@selector(stringValue)]) {
            val = [val stringValue];
        }
        if (![val isKindOfClass:[NSString class]]) {
            continue;
        }
        [request setValue:val forHTTPHeaderField:key];
    }

    __block NSURLSessionUploadTask *uploadTask = nil;
    uploadTask = [manager uploadTaskWithRequest:request
                                       fromData:data
                                       progress:nil
                              completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                                  if (error) {
                                      NSString *message = [responseObject  objectForKey:@"msg"];
                                      message = error.localizedDescription;
                                      if(failure){
                                          failure(uploadTask,error);
                                      }

                                      NSLog(@"Error: %@", error);
                                  } else {
                                      NSLog(@"%@ %@", response, responseObject);
                                      if(success){
                                          success(uploadTask,responseObject);
                                      }
                                  }
                              }];
    [uploadTask resume];

    return uploadTask;
}

- (NSURLSessionDataTask *)downloadImageFile:(NSString *)URLString
                                   cacheURL:(NSURL *)cacheUrl
                           downloadProgress:(void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                    success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                                    failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    AFOAuthManager *manager = nil;
    NSURL *URL = nil;
    if([URLString hasPrefix:@"https://"] || [URLString hasPrefix:@"http://"]){
        URL = [NSURL URLWithString:URLString];
        manager = [[AFOAuthManager alloc] initWithSessionConfiguration:nil];
    }else{
        URL = [NSURL URLWithString:URLString relativeToURL:self.baseURL];
        manager = self.defaultManager;
    }
    manager.responseSerializer = [AFImageResponseSerializer serializer];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    //NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    [request setHTTPMethod:@"GET"];
    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
    __block NSURL *storageUrl = [cacheUrl copy];
    __block NSURLSessionDownloadTask *downloadTask =nil;
    downloadTask = [manager downloadTaskWithRequest:request
                                           progress:^(NSProgress *downloadProgress){
                                               if(downloadProgressBlock){
                                                   downloadProgressBlock(downloadProgress);
                                               }
                                           }
                                        destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
                                            return storageUrl;

                                        } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
                                            if(!error){
                                                if(success){
                                                    success(downloadTask,filePath);
                                                }
                                            }else{
                                                if(failure){
                                                    failure(downloadTask,error);
                                                }
                                            }
                                            NSLog(@"File downloaded to: %@", filePath);
                                        }];
    [downloadTask resume];

    return downloadTask;
}

- (NSURLSessionDataTask *)downloadFile:(NSString *)URLString
                          headerAccept:(NSString *)headerAccept
                              cacheURL:(NSURL *)cacheUrl
                      downloadProgress:(void (^)(NSProgress *downloadProgress))downloadProgressBlock
                               success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                               failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    AFOAuthManager *manager = nil;
    NSURL *URL = nil;
    if([URLString hasPrefix:@"https://"] || [URLString hasPrefix:@"http://"]){
        URL = [NSURL URLWithString:URLString];
        manager = [[AFOAuthManager alloc] initWithSessionConfiguration:nil];
    }else{
        URL = [NSURL URLWithString:URLString relativeToURL:self.baseURL];
        manager = self.defaultManager;
    }
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    //[AFImageResponseSerializer serializer];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    //NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    [request setHTTPMethod:@"GET"];
    if (headerAccept) {
        [request addValue:headerAccept forHTTPHeaderField:@"Accept"];
    }
    __block NSURL *storageUrl = [cacheUrl copy];
    __block NSURLSessionDownloadTask *downloadTask =nil;
    downloadTask = [manager downloadTaskWithRequest:request
                                           progress:^(NSProgress *downloadProgress){
                                               if(downloadProgressBlock){
                                                   downloadProgressBlock(downloadProgress);
                                               }
                                           }
                                        destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {

                                            /*
                                            NSString *filename =  [response suggestedFilename];
                                            NSString * path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

                                            NSURL *localPath = [NSURL URLWithString:filename relativeToURL:path];
                                            return localPath;
                                             */
                                            return storageUrl;

                                        } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
                                            if(!error){
                                                if(success){
                                                    success(downloadTask,filePath);
                                                }
                                            }else{
                                                if(failure){
                                                    failure(downloadTask,error);
                                                }
                                            }
                                            NSLog(@"File downloaded to: %@", filePath);
                                        }];
    [downloadTask resume];

    return downloadTask;

}


- (NSURLSessionDataTask *)YuanXinDownloadImageFile:(NSString *)URLString
                                        parameters:(id)parameters
                                  downloadProgress:(void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                           success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                                           failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{

    //[manager.requestSerializer setAuthorizationHeaderFieldWithCredential:credential];
    AFHTTPSessionManager *manager = nil;
    NSURL *URL = nil;
    if([URLString hasPrefix:@"https://"] || [URLString hasPrefix:@"http://"]){
        URL = [NSURL URLWithString:URLString];
        manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:_configuration];
    }else{
        URL = [NSURL URLWithString:URLString relativeToURL:self.baseURL];
        manager = self.defaultManager;
    }
    //manager.responseSerializer = [AFImageResponseSerializer serializer]; // 告诉服务器以图片格式返回数据
    manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // 直接使用服务器应该返回的数据，不做任何解析，需要我们接到数据后自己去转换
    //NSSet *acceptableContentTypes = [NSSet setWithSet:manager.responseSerializer.acceptableContentTypes];
    //manager.responseSerializer.acceptableContentTypes = [acceptableContentTypes setByAddingObjectsFromSet:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", nil]];

    __block NSURLSessionDownloadTask *downloadTask =nil;

    downloadTask = [manager GET:URLString
                     parameters:parameters
                       progress:nil
                        success:^(NSURLSessionDataTask *task, id _Nullable responseObject){
                            if(success){
                                UIImage *image = responseObject;
                                if ([responseObject isKindOfClass:[NSData class]]) {
                                    image = [UIImage imageWithData:responseObject];
                                }
                                success(task,image);
                            }
                        }
                        failure:^(NSURLSessionDataTask * _Nullable task, NSError *error){
                            if(failure){
                                failure(task,error);
                            }
                        }];
    return downloadTask;

}


- (AFOAuthManager *)getCurrentManagerWithUrl:(NSString *)URLString{
    AFOAuthManager *manager = nil;
    if([URLString hasPrefix:@"https://"] || [URLString hasPrefix:@"http://"]){
        manager = [[AFOAuthManager alloc] initWithSessionConfiguration:nil];
    }else{
        manager = self.defaultManager;
    }
    return manager;
}


- (NSURL *)getCurrentUrl:(NSString *)URLString{

    NSURL *url = nil;
    if([URLString isUrl]){
        url = [NSURL URLWithString:URLString];
    }else{
        url = [NSURL URLWithString:URLString relativeToURL:self.baseURL];
    }
    return url;
}

- (AFSecurityPolicy *)customSecurityPolicy{
    // /先导入证书
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"aa" ofType:@"cer"];//证书的路径
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    // AFSSLPinningModeCertificate 使用证书验证模式
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    // allowInvalidCertificates 是否允许无效证书（也就是自建的证书），默认为NO
    // 如果是需要验证自建证书，需要设置为YES
    securityPolicy.allowInvalidCertificates = YES;

    //validatesDomainName 是否需要验证域名，默认为YES；
    //假如证书的域名与你请求的域名不一致，需把该项设置为NO；如设成NO的话，即服务器使用其他可信任机构颁发的证书，也可以建立连接，这个非常危险，建议打开。
    //置为NO，主要用于这种情况：客户端请求的是子域名，而证书上的是另外一个域名。因为SSL证书上的域名是独立的，假如证书上注册的域名是www.google.com，那么mail.google.com是无法验证通过的；当然，有钱可以注册通配符的域名*.google.com，但这个还是比较贵的。
    //如置为NO，建议自己添加对应域名的校验逻辑。
    securityPolicy.validatesDomainName = NO;

    securityPolicy.pinnedCertificates = [NSSet setWithArray:@[certData]];

    return securityPolicy;
}


@end
